package mmc.cell3;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import mmc.Constants;
import mmc.Settings;
import mmc.cell.CellPosition;
import mmc.cell.ServerCell;
import mmc.cell.ServerCellProvider;
import mmc.cell.ServerCellStorage;

public class ServerCellStorageImpl implements ServerCellStorage{
	private Set<ServerCell> dirtyCells = new HashSet<ServerCell>();
	private ServerCellProvider cp;
	
	public ServerCellStorageImpl(Cell3Provider cp){
		this.cp=cp;
	}
	
	@Override
	public void markCellsAsDirty(Collection<ServerCell> chunks) {
		synchronized(dirtyCells){
			dirtyCells.addAll(chunks);			
		}
	}

	public boolean isChunkAvailable(CellPosition p){
		return false;
	}
	
	public ServerChunk loadChunk(CellPosition p){
		return null;
	}
	
	@Override
	public void setAutoSave(boolean autoSave) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void forceSave() {
		try {
			ServerCellManagerImpl cm = (ServerCellManagerImpl) cp.getCellManager();
			File f = new File(Settings.CELL_FULL_STORAGE_FILE);
			ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(f));
			DataOutputStream dos = new DataOutputStream(zos);
			
			Map<CellPosition, ServerChunk> chunks = cm.getLoadedChunks();
			
			synchronized (chunks) {
				for(ServerChunk chunk : chunks.values()){
					zos.putNextEntry(new ZipEntry(chunk.toString()));
					List<ServerCell> cells = chunk.getCells();
					synchronized(cells){
						for(ServerCell cell : cells){
							int solid = cell.solid;
							dos.writeInt(solid);
							if(!cell.isCompressed()){
								dos.write(cell.block);
							}
						}
					}
					zos.closeEntry();
				}
			}
			
			dos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void forceLoad() {
		try {
			ServerCellManagerImpl cm = (ServerCellManagerImpl) cp.getCellManager();
			File f = new File(Settings.CELL_FULL_STORAGE_FILE);
			ZipInputStream zis = new ZipInputStream(new FileInputStream(f));
			DataInputStream dis = new DataInputStream(zis);
			ZipEntry entry;
			
			try{
				while((entry=zis.getNextEntry())!=null){
					CellPosition pos = new CellPosition(entry.getName());
					ServerChunk c = new ServerChunk(pos);
					
					for(int i=0;i<Constants.CHUNK_CELLS;i++)
						for(int j=0;j<Constants.CHUNK_CELLS;j++)
							for(int k=0;k<Constants.CHUNK_CELLS;k++){
								CellPosition cp = new CellPosition(pos.x + i*Constants.CELL_SIZE, pos.y + j*Constants.CELL_SIZE, pos.z + k*Constants.CELL_SIZE);
								ServerCell cell;
								int solid = dis.readInt();
								
								if(solid==ServerCell.CELL_NOT_COMPRESSED){
									byte[] data = new byte[Constants.CELL_SIZE3];
									int progress=0;
									int ret;
									while(data.length!=(progress+=(ret = dis.read(data, progress, data.length-progress)))){
										if(ret==ServerCell.CELL_NOT_COMPRESSED)
											throw new RuntimeException("EOF reached too early: "+(progress+1));
									}
									
									cell = new ServerCell(cp, data);
								}else{
									cell = new ServerCell(cp, solid);
								}
								
								c.cells.add(cell);
								//System.out.print(".");
							}
					
					//System.out.println("\nCHUNK "+c+" finished");
					cm.loadChunk(c);
					
					zis.closeEntry();
				}
			}finally{
				dis.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
